#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LEFT "["
#define RIGHT "]"
#define LINE_SIZE 1024
#define DIVIDESYMBOL " \t"
#define MAXARGC 32
#define EXITCODE 13
#define NONE -1
#define IN_RDIR 0
#define OUT_RDIR 1
#define ADD_RDIR 2


char commond[LINE_SIZE];
char* argv[MAXARGC];
int lastcode = 0; //最后一个进程的退出码
char PWD[LINE_SIZE];
char myenv[LINE_SIZE];//自定义环境变量表

char* rdir_file = NULL; //重定向的文件名
int rdir_type = NONE; //重定向的类型(输入、输出、追加)


//重定向处理
void check_rdir(char* _commond)
{   
    char* pos = _commond;
    while(*pos)
    {
        if(*pos == '>')//输出重定向
        {
            
            rdir_file = pos + 1;
            if(*(pos + 1) == '>')
            {
                //追加重定向
                rdir_type = ADD_RDIR;
                *pos = '\0';
                break;
            }
            rdir_type = OUT_RDIR;
            *pos = '\0';
            break;
        }
        else if(*pos == '<')//输入重定向
        {
             *pos = '\0';   
            rdir_file = pos + 1;
            rdir_type = IN_RDIR;
            break;
        }
        else
        {
            pos++;
        }
    }
}

//交互界面
void getpwd()
{
    getcwd(PWD,sizeof(PWD));
}

void interact()
{
    getpwd();
    printf(LEFT"%s""@""%s"RIGHT":~",getenv("USER"),PWD);
    fgets(commond,sizeof(commond),stdin);
    int commond_len = strlen(commond);
    commond[commond_len - 1] = '\0';
    check_rdir(commond);
}

//构建argv
int divideCommond()
{
    int i = 0;
    argv[i++] = strtok(commond,DIVIDESYMBOL);
    while(argv[i++] = strtok(NULL,DIVIDESYMBOL));
    return i- 1; 
}


//执行指令
int normalExecute()
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return -1;
    }
    else if(id == 0)//子进程
    {
        //重定向处理
        if(rdir_type == OUT_RDIR)
        {
            int fd = open(rdir_file,O_WRONLY|O_CREAT|O_TRUNC,0666);
            dup2(fd,1);
        }
        if(rdir_type == IN_RDIR)
        {   
            int fd = open(rdir_file,O_RDONLY);
            dup2(fd,0);    
        } 
        if(rdir_type == ADD_RDIR)
        {   
            int fd = open(rdir_file,O_WRONLY|O_CREAT|O_APPEND,0666);
            dup2(fd,1);    
        }    

        execvp(argv[0],argv);
        exit(EXITCODE);  
    }
    else//父进程
    {
        int status = 0;
        waitpid(-1,&status,0);
        if(!WIFEXITED(status))
        {
            perror("waitpid error");
            printf("id:%d",id);
        }
        else
        {
            lastcode = WEXITSTATUS(status);
        }
    }
}

//内建指令的特殊处理
int buildCommand(int _argc)
{
    //cd
    if(_argc == 2 && strcmp(argv[0],"cd") == 0 )
    {
        chdir(argv[1]);
        return 1;
    }
    else if(_argc == 2 && strcmp(argv[0], "export") == 0){
        strcpy(myenv, argv[1]);
        putenv(myenv);
        return 1;
    }
    else if(_argc == 2 && strcmp(argv[0], "echo") == 0){
        if(strcmp(argv[1], "$?") == 0)
        {
            printf("%d\n", lastcode);
            lastcode=0;
        }
        else if(*argv[1] == '$'){
            char *val = getenv(argv[1]+1);
            if(val) printf("%s\n", val);
        }
        else{
            printf("%s\n", argv[1]);
        }

        return 1;
    }

    if(strcmp(argv[0], "ls") == 0)
    {
        argv[_argc++] = "--color";
        argv[_argc] = NULL;
    }
    return 0;
}

int main()
{
    while(1)
    {
        //显示交互界面（当前路径、当前用户..）
        interact();
        // printf("%s",commond);

        //把指令分割
        int argc = divideCommond();
        // for(int i = 0;i<argc;i++)
        // {
        //     printf("%s\n",argv[i]);
        // }
        
        int isBuildCommond = 0;
        isBuildCommond = buildCommand(argc);
        if(!isBuildCommond)
            normalExecute();
    }
    return 0;
}